package org.utils.zip;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

import org.apache.log4j.Logger;
import org.utils.io.FileUtils;

public class ArchiveManager
{
	public static final long SIZE_UNLIMITED = -1;
	public static final int BUFFER_SIZE = 4096;

//	private String filename = null;
	private long maxArchiveSize = SIZE_UNLIMITED;

	public ArchiveManager()
	{
	}

	public void setArchiveMaxSize(long archiveSize)
	{
		this.maxArchiveSize = archiveSize;
	}

	public long getArchiveMaxSize()
	{
		return this.maxArchiveSize;
	}

	public void extractArchive(String pFilename, String extractDir) throws IOException
	{
		ZipInputStream in = new ZipInputStream(new FileInputStream(pFilename));
		File root = new File(extractDir);
		root.mkdirs();
		ZipEntry entry = null;
		while ((entry = in.getNextEntry()) != null)
		{
		   try {
			//File path = new File(root + entry.getComment());
			Logger.getLogger(this.getClass()).info("Extracting file: "+entry.getName());//+" to: "+path.getPath());
			//path.mkdirs();
			File f = new File(root, entry.getName());
			f.getParentFile().mkdirs();
			if (f.createNewFile())
			   writeDataToFile(in, f);
			else
			   System.err.println("Can't create file: "+entry.getName());
		   } catch (IOException e) {
			System.err.println("Can't extract file: "+entry.getName()+System.getProperty("line.separator")+e.toString());
		   }
		}
		in.close();
	}

	public void writeDataToFile(InputStream in, File f) throws IOException
	{
		FileOutputStream out = new FileOutputStream(f);
		byte[] buffer = new byte[BUFFER_SIZE];
		int readSize = -1;
		while ((readSize = in.read(buffer)) != -1)
		{
			out.write(buffer, 0, readSize);
		}
		out.close();
	}

	public void createArchive(String filename, String[] filenames) throws IOException
	{
		File[] lfiles = new File[filenames.length];
		for (int i = 0; i < filenames.length; i++)
			lfiles[i] = new File(filenames[i]);
		createArchive(filename, lfiles);
	}

	public void createArchive(String filename, File[] files) throws IOException
	{
		int pos = filename.lastIndexOf('.');
		String baseName = filename.substring(0, pos);
		String extension = filename.substring(pos);
		ZipOutputStream out = new ZipOutputStream(new FileOutputStream(filename));
		long currentFileSize = 0;
		int archiveCount = 0;
		for (int i = 0; i < files.length; i++)
		{
		    File currentFile = files[i];
		    try {
			Logger.getLogger(this.getClass()).info("Adding file: "+currentFile.getName()+" ");
			String path = currentFile.getPath();
			path = path.substring(0, path.lastIndexOf('\\'));
			Logger.getLogger(this.getClass()).info("File Path: "+path);
			ZipEntry entry = new ZipEntry(currentFile.getPath());//getName());
			entry.setSize(currentFile.length());
			entry.setTime(currentFile.lastModified());
			//entry.setComment(path);
			out.putNextEntry(entry);
			addFileData(currentFile, out);
			out.closeEntry();
			currentFileSize += entry.getSize();
			if (getArchiveMaxSize() == SIZE_UNLIMITED)
				continue ;
			if (currentFileSize >= getArchiveMaxSize())
			{
				out.close();
				archiveCount++;
				currentFileSize = 0;
				out = new ZipOutputStream(new FileOutputStream(baseName+"_"+archiveCount+extension));
			}
		    } catch (IOException e) {
			System.err.println("Can't add file named: "+currentFile.getName()+System.getProperty("line.separator")+e.toString());
		    }
		}
		out.close();
	}

	public void addFileData(File f, OutputStream out) throws IOException
	{
		FileInputStream in = new FileInputStream(f);
		byte[] buffer = new byte[BUFFER_SIZE];
		int readSize = -1;
		while ((readSize = in.read(buffer)) != -1)
		{
			out.write(buffer, 0, readSize);
		}
		in.close();
	}

	public static void main(String[] args) throws IOException
	{
		if (args.length == 0)
			return ;
		ArchiveManager manager = new ArchiveManager();
		if (args[0].equals("extract"))
		{
			manager.extractArchive(args[1], args[2]);
		}
		else
		{
			manager.setArchiveMaxSize(ArchiveManager.SIZE_UNLIMITED);//2*1024*1024
			String[] lfiles = FileUtils.getFileListInDirectory(args[2]);
			manager.createArchive(args[1], lfiles);
		}
	}
}
